from datetime import datetime, timedelta
from typing import Optional

from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from pydantic import BaseModel, ValidationError
from passlib.context import CryptContext
from apps.utils.database import get_write_db, get_read_db
from sqlalchemy.orm import Session
from apps.blueprints.user.models import User
import config
from apps.blueprints.user import schemas


# 要返回的token格式
class Token(BaseModel):
    access_token: str
    token_type: str

# # 要返回的用户格式
# class UserBase(BaseModel):
#     contact_number: int
#     email: Optional[str] = None
#     nickname: Optional[str] = None
#
# class UserInDB(UserBase):
#     hashed_password: str

# 密码加密模式
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# 认证模式
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/token/")


# 校验密码
def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)


# 密码哈希
def get_password_hash(password):
    return pwd_context.hash(password)


# 通过id获取用户
def jwt_get_user(db: Session, user_id: int):
    try:
        user = db.query(User).get(user_id)
        # return schemas.User(**user.to_dict())
        return user.to_dict()
    except:
        raise HTTPException(
        status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )


# 生成token，带有过期时间
def create_access_token(data: dict):
    to_encode = data.copy()
    expire = datetime.utcnow() + timedelta(minutes=config.ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, config.SECRET_KEY, algorithm=config.ALGORITHM)

    return encoded_jwt


# 解密token返回用户信息
def jwt_get_current_user(token: str = Depends(oauth2_scheme), db: Session = Depends(get_read_db)):
    credentials_exception = HTTPException(
        status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token=token, key=config.SECRET_KEY, algorithms=[config.ALGORITHM])
        user_id = payload.get("id")
        if user_id is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception
    except (JWTError, ValidationError):
        raise credentials_exception
    user = jwt_get_user(db, user_id=int(user_id))
    return user